package com.sdy.healthcode.biz.utils;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * 二维码图片生成
 * @author Administrator
 *
 */
public class QrCodeUtil {
    private static final Logger logger = LoggerFactory.getLogger(QrCodeUtil.class);

    /**
     * 生成二维码，输出流
     * @param imgType "png"
     * @param outputStream
     * @param content
     * @param size
     */
    public static void createQrCode(
            String imgType,
            OutputStream outputStream,
            String content,
            Color frontColor,
            Color backgroundColor,
            BufferedImage image,
            int size) throws Exception {
        try {
            //生成二维码
            BitMatrix bitMatrix = createBitMatrix(content, size, size);
            renderImgMatrix(bitMatrix, frontColor, backgroundColor, image, imgType, outputStream);
        } catch (WriterException | IOException e) {
            logger.error("二维码生成失败。", e);
            throw e;
        }
    }
    
    private static BitMatrix createBitMatrix(String content, int width, int height) throws WriterException {
        //定义二维码的参数
        Map<EncodeHintType, Object> map = new HashMap<>();
        //设置编码
        map.put(EncodeHintType.CHARACTER_SET, "utf-8");
        //设置纠错等级
        map.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.Q);
        map.put(EncodeHintType.MARGIN, 2);
        //生成二维码
        return new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, map);
    }
    
    private static void renderImgMatrix(BitMatrix matrix, Color frontColor, Color backgroundColor, BufferedImage image, String imgType, OutputStream outputStream) throws IOException {
        final int imageWidth = matrix.getWidth() / 6;
        final int imageHeight = matrix.getHeight() / 6;
        final int imageHalfWidth = imageWidth / 2;
        final int frameWidth = 2;
        BufferedImage scaledImage = scale(image, imageWidth, imageHeight);
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        int halfw = width / 2;
        int halfh = height / 2;
        int[] pixels = new int[matrix.getWidth() * matrix.getHeight()];
        frontColor = frontColor == null ? Color.BLACK : frontColor;
        backgroundColor = backgroundColor == null ? Color.WHITE : backgroundColor;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                if (scaledImage != null) {
                    if (x > halfw - imageHalfWidth
                            && x < halfw + imageHalfWidth
                            && y > halfh - imageHalfWidth
                            && y < halfh + imageHalfWidth) {
                        pixels[y * width + x] = scaledImage.getRGB(x - halfw + imageHalfWidth, y - halfh + imageHalfWidth);
                    } else if ((x > halfw - imageHalfWidth - frameWidth
                            && x < halfw - imageHalfWidth + frameWidth
                            && y > halfh - imageHalfWidth - frameWidth && y < halfh + imageHalfWidth + frameWidth)
                            || (x > halfw + imageHalfWidth - frameWidth
                            && x < halfw + imageHalfWidth + frameWidth
                            && y > halfh - imageHalfWidth - frameWidth && y < halfh + imageHalfWidth + frameWidth)
                            || (x > halfw - imageHalfWidth - frameWidth
                            && x < halfw + imageHalfWidth + frameWidth
                            && y > halfh - imageHalfWidth - frameWidth && y < halfh - imageHalfWidth + frameWidth)
                            || (x > halfw - imageHalfWidth - frameWidth
                            && x < halfw + imageHalfWidth + frameWidth
                            && y > halfh + imageHalfWidth - frameWidth && y < halfh + imageHalfWidth + frameWidth)) {
                        pixels[y * width + x] = backgroundColor.getRGB();
                    } else {
                        pixels[y * width + x] = matrix.get(x, y) ? frontColor.getRGB() : backgroundColor.getRGB();
                    }
                } else {
                    pixels[y * width + x] = matrix.get(x, y) ? frontColor.getRGB() : backgroundColor.getRGB();
                }
            }
        }
        bufferedImage.getRaster().setDataElements(0, 0, width, height, pixels);
        ImageIO.write(bufferedImage, imgType, outputStream);
    }

    /**
     * 把传入的原始图像按高度和宽度进行缩放，生成符合要求的图标
     *
     * @param srcImage     源文件
     * @param height       目标高度
     * @param width        目标宽度
     */
    private static BufferedImage scale(BufferedImage srcImage, int width, int height) {
        if (srcImage == null) {
            return null;
        }
        // 缩放比例
        double wh1 = srcImage.getWidth() * 1.0 / srcImage.getHeight();
        double wh2 = width * 1.0 / height;
        Image destImage;
        if (wh1 > wh2) {
            destImage = srcImage.getScaledInstance(width, (int)(width * 1.0 / wh1), BufferedImage.SCALE_SMOOTH);
        } else {
            destImage = srcImage.getScaledInstance((int)(height * wh1), height, BufferedImage.SCALE_SMOOTH);
        }
        // 补白
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphic = image.createGraphics();
        graphic.setColor(Color.white);
        graphic.fillRect(0, 0, width, height);
        if (width == destImage.getWidth(null)) {
            graphic.drawImage(destImage, 0,
                    (height - destImage.getHeight(null)) / 2,
                    destImage.getWidth(null), destImage.getHeight(null),
                    Color.white, null);
        } else {
            graphic.drawImage(destImage,
                    (width - destImage.getWidth(null)) / 2, 0,
                    destImage.getWidth(null), destImage.getHeight(null),
                    Color.white, null);
        }
        graphic.dispose();
        destImage = image;
        return (BufferedImage) destImage;
    }
	
	public static void main(String[] args) throws Exception {
        BufferedImage srcImage = ImageIO.read(new File("healthcode-web/src/main/resources/qrlogo.jpg"));
        createQrCode("png", new FileOutputStream("qrcode1.png"), "22315351432543251535143254325432523525423522", Color.RED, null, srcImage, 500);
    }
}
